﻿using System;
using System.Collections.Generic;
using UnityEngine;

namespace Core
{
    public static class Iterators
    {
        public static bool stl_contains<T>(T[] arr, T value)
           where T : struct, IComparable<T>
        {
            return stl_contains(arr, value, 0, arr.Length);
        }

        public static bool stl_contains<T>(this T[] arr, T value, int min, int max)
            where T : struct, IComparable<T>
        {
            max = Mathf.Min(arr.Length, max);

            for (int i = min; i < max; i++)
            {
                if (arr[i].CompareTo(value) == 0)
                {
                    return true;
                }
            }
            return false;
        }

        public static bool stl_all<T>(this IList<T> data, Func<T, bool> func)
        {
            if (func == null || data == null)
            {
                return false;
            }

            for (int i = 0; i < data.Count; i++)
            {
                var t = data[i];
                if (func(t) == false)
                {
                    return false;
                }
            }
            return true;
        }


        public static bool stl_any<T>(this IList<T> data, Func<T, bool> func)
        {
            if (func == null || data == null)
            {
                return false;
            }

            for (int i = 0; i < data.Count; i++)
            {
                var t = data[i];
                if (func(t))
                {
                    return true;
                }
            }
            return false;
        }

        public static void stl_sort<T>(this IList<T> data, Func<T, T, int> func)
        {
            if (func == null || data == null || data.Count < 2)
            {
                return;
            }

            for (int i = data.Count - 1; i > 0; i--)
            {
                for (int j = 0; j < i; j++)
                {
                    if (func(data[j], data[j + 1]) > 0)
                    {
                        (data[j + 1], data[j]) = (data[j], data[j + 1]);
                    }
                }
            }
        }

        public static void stl_quick_sort(this IList<int> list)
        {
            if (list == null || list.Count < 2)
            {
                return;
            }

            quick_sort_recursive(list, 0, list.Count);
        }

        private static void quick_sort_recursive(IList<int> list, int start, int end)
        {
            if (start >= end) return;

            int mid = list[end];
            int left = start;
            int right = end - 1;

            while (left < right)
            {
                while (list[left] < mid && left < right)
                {
                    left++;
                }

                while (list[right] >= mid && left < right)
                {
                    right--;
                }

                Swap(list, left, right);
            }

            if (list[left] >= list[right])
            {
                Swap(list, left, right);
            }
            else
            {
                left++;
            }

            quick_sort_recursive(list, start, left - 1);
            quick_sort_recursive(list, left + 1, end);
        }

        private static void Swap<T>(IList<T> list, int start, int end)
        {
            (list[end], list[start]) = (list[start], list[end]);
        }


        /// <summary>
        /// for循环
        /// x 从s_x到e_x 步长为step_x
        /// y 从s_y到e_y 步长为step_y
        /// </summary>
        /// <param name="s_x"></param>
        /// <param name="e_x"></param>
        /// <param name="step_x"></param>
        /// <param name="s_y"></param>
        /// <param name="e_y"></param>
        /// <param name="step_y"></param>
        /// <param name="func"></param>
        public static void stl_for(int s_x, int e_x, int step_x, int s_y, int e_y, int step_y, Action<int, int> func)
        {
            if (func == null) return;

            for (int j = s_y; j < e_y; j += step_y)
            {
                for (int i = s_x; i < e_x; i += step_x)
                {
                    func(i, j);
                }
            }
        }
        public static void stl_foreach<T>(this IList<T> src_list, Action<T> func)
        {
            if (src_list == null || func == null) return;

            for (int i = 0; i < src_list.Count; i++)
            {
                func(src_list[i]);
            }
        }

        public static void stl_findAll<T>(this IList<T> src_lst, IList<T> tgt_lst, Predicate<T> func)
        {
            if (func == null || src_lst == null || tgt_lst == null) return;

            tgt_lst.Clear();

            for (int i = 0; i < src_lst.Count; i++)
            {
                var c = src_lst[i];
                if (func(c))
                {
                    tgt_lst.Add(c);
                }
            }
        }

        public static int stl_count<T>(this IList<T> src_lst, Predicate<T> func)
        {
            if (func == null) return 0;

            int cnt = 0;
            for (int i = 0; i < src_lst.Count; i++)
            {
                var c = src_lst[i];
                if (func(c))
                {
                    cnt++;
                }
            }

            return cnt;
        }

        public static int stl_indexOf<T>(this IList<T> src_lst, Predicate<T> func)
        {
            if (src_lst == null || func == null) return -1;

            for (int i = 0; i < src_lst.Count; i++)
            {
                var c = src_lst[i];
                if (func(c))
                {
                    return i;
                }
            }
            return -1;
        }

        public static void stl_except<T>(List<T> exceptList, List<T> list1, List<T> list2)
        {
            exceptList.Clear();

            for (int i = 0; i < list1.Count; i++)
            {
                var t = list1[i];
                if (list2.Contains(t))
                {
                    continue;
                }
                exceptList.Add(t);
            }
        }

        #region For
        /// <summary>
        /// for循环
        /// 默认从0开始遍历，步长为1
        /// </summary>
        /// <param name="w"></param>
        /// <param name="h"></param>
        /// <param name="func"></param>
        public static void stl_for(int w, int h, Action<int, int> func)
        {
            if (func == null) return;

            for (int j = 0; j < h; j++)
            {
                for (int i = 0; i < w; i++)
                {
                    func(i, j);
                }
            }
        }

        /// <summary>
        /// 螺旋形型遍历，从00点开始，由外向内遍历
        /// </summary>
        /// <param name="w"></param>
        /// <param name="h"></param>
        /// <param name="func"></param>
        public static void spiral_for(int w, int h, Action<int, int> func)
        {
            if (func == null) return;

            int min_x = 0;
            int max_x = w - 1;
            int min_y = 0;
            int max_y = h - 1;

            int x1 = min_x, y1 = min_y;
            int dir_x = 1, dir_y = 0;

            while (true)
            {
                //Do(x1, y1, func);
                func(x1, y1);

                if (min_x > max_x || min_y > max_y)
                {
                    break;
                }

                x1 += dir_x;
                y1 += dir_y;
                if (dir_x == 1 && x1 >= max_x)
                {
                    dir_x = 0;
                    dir_y = 1;
                    min_y++;
                    continue;
                }
                if (dir_y == 1 && y1 >= max_y)
                {
                    dir_y = 0;
                    dir_x = -1;
                    max_x--;
                    continue;
                }
                if (dir_x == -1 && x1 <= min_x)
                {
                    dir_x = 0;
                    dir_y = -1;
                    max_y--;
                    continue;
                }
                if (dir_y == -1 && y1 <= min_y)
                {
                    dir_y = 0;
                    dir_x = 1;
                    min_x++;
                    continue;
                }
            }
        }


        /// <summary>
        /// 左右分离型遍历
        /// </summary>
        /// <param name="w"></param>
        /// <param name="h"></param>
        /// <param name="func"></param>
        /// <param name="cnt"></param>
        public static void lr_for(int w, int h, Action<int, int> func, int cnt = int.MaxValue)
        {
            if (cnt <= 0 || func == null) return;
            cnt = Mathf.Min(cnt, w * h);

            int len = cnt / 2;

            for (int k = 0; k < len; k++)
            {
                int i = k / h;
                int j = k % h;

                func(i, j);

                func(w - i - 1, h - j - 1);
            }

            if (len * 2 == cnt - 1)
            {
                int i = len / h;
                int j = len % h;

                func(i, j);
            }
        }

        #endregion
    }
}
